package com.zmc.coupon.application.impl;

import com.zmc.common.annotation.PreventRepeatSubmit;
import com.zmc.common.domain.es.EsSkuEntity;
import com.zmc.common.domain.query.coupon.CouponEsFeignQuery;
import com.zmc.common.domain.query.coupon.CouponFeignQuery;
import com.zmc.common.domain.vo.coupon.CouponReduceVo;
import com.zmc.common.domain.vo.coupon.CouponSkuVo;
import com.zmc.common.domain.vo.coupon.CouponUpdateVo;
import com.zmc.common.enums.RequestSourceEnum;
import com.zmc.common.exception.base.WebDisplayException;
import com.zmc.common.utils.JsonUtils;
import com.zmc.common.utils.PageUtils;
import com.zmc.common.utils.R;
import com.zmc.common.utils.redis.RedisCache;
import com.zmc.common.utils.token.AuthTokenService;
import com.zmc.common.utils.uuid.IdUtils;
import com.zmc.coupon.application.CouponApplicationService;
import com.zmc.coupon.application.construct.CouponConstructService;
import com.zmc.coupon.constants.CouponConstant;
import com.zmc.coupon.enums.CouponEnum;
import com.zmc.coupon.feign.SearchFeignService;
import com.zmc.coupon.infrastructure.bean.vo.CouponReceiveVo;
import com.zmc.coupon.infrastructure.entity.CouponEntity;
import com.zmc.coupon.infrastructure.entity.CouponHistoryEntity;
import com.zmc.coupon.infrastructure.entity.CouponSkuEntity;
import com.zmc.coupon.infrastructure.service.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @Author：zmc
 * @Date：2024/12/6 12:11
 */

@Service
public class CouponApplicationServiceImpl implements CouponApplicationService {

    public static final Logger log = LoggerFactory.getLogger(CouponApplicationServiceImpl.class);

    @Autowired
    private CouponConstructService couponConstructService;

    @Autowired
    private CouponService couponService;

    @Autowired
    private CouponHistoryService couponHistoryService;

    @Autowired
    private CouponSkuService couponSkuService;

    @Autowired
    private SkuFullReductionService skuFullReductionService;

    @Autowired
    private SkuLadderService skuLadderService;

    @Autowired
    private SearchFeignService searchFeignService;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private AuthTokenService authTokenService;

    @Override
    public R getCouponDetail(CouponFeignQuery query) {
        return R.ok(couponConstructService.create(query.getSkuIds()).coupon(query.getType()).reduction().ladder().list());
    }

    @Override
    @Transactional
    @PreventRepeatSubmit(lockByPerson = true, source = RequestSourceEnum.WEB)
    public boolean receiveCoupon(CouponReceiveVo vo) {
        String lockKey = getCouponReceiveKey(authTokenService.getMemberInfo().getMemberId());
        String value = IdUtils.fastUUID();
        Boolean lock = redisCache.setCacheIfAbsent(lockKey, value, 10, TimeUnit.SECONDS);
        if (Boolean.TRUE.equals(lock)) {
            try{
                Long couponId = vo.getCouponId();
                //优惠卷已不存在
                CouponEntity couponEntity = couponService.getById(vo.getCouponId());
                if (couponEntity == null) {
                    return false;
                }
                //卷是否超过已用完、不在领取时间内
                LocalDateTime now = LocalDateTime.now();
                if (couponEntity.getReceiveCount() >= couponEntity.getPublishCount() || now.isBefore(couponEntity.getEnableStartTime()) ||
                now.isAfter(couponEntity.getEnableEndTime())) {
                    return false;
                }
                //查询用户优惠卷领取记录
                List<CouponHistoryEntity> list = couponHistoryService.getCouponHistory(vo);
                //若有未使用优惠卷，则不能领取
                long count = list.stream().filter(item -> item.getUseType() == CouponEnum.COUPON_USE_TYPE_NOT_USE.getCode()).count();
                if (count > 0) {
                    return false;
                }
                //当前商品已不参加优惠卷活动
                CouponSkuEntity couponSkuEntity = couponSkuService.getSpuRelation(vo);
                if (couponSkuEntity == null) {
                    return false;
                }
                //若当前未领取或领取数量小于每人限领张数，则领取优惠卷
                if (CollectionUtils.isEmpty(list) || list.size() < couponEntity.getPerLimit()) {
                    boolean flag = couponService.receiveCoupon(couponId);
                    //领取成功,录入优惠券领取历史记录
                    if (flag) {
                        couponHistoryService.createCouponHistory(vo);
                    }
                    return flag;
                }
            } finally {
                if (Objects.equals(redisCache.getCacheObject(lockKey), value)){
                    redisCache.deleteObject(lockKey);
                }
            }
        }
        return false;
    }

    @Override
    @Transactional
    @PreventRepeatSubmit(lockByPerson = true, source = RequestSourceEnum.MANAGE)
    public void removeById(Long couponId) {
        //删除优惠卷
        couponService.removeById(couponId);
        //删除优惠卷关联商品关系
        couponSkuService.removeByCouponId(couponId);
    }

    @Override
    @Transactional
    @PreventRepeatSubmit(key = "#vo.orderSn", openSpEL = true)
    public void reduceCoupon(CouponReduceVo vo) {
        List<CouponHistoryEntity> list = couponHistoryService.listByIds(vo.getHistoryIds());
        Map<Long, Long> couponMap = new HashMap<>();
        list.forEach(item -> {
            item.setOrderSn(vo.getOrderSn());
            item.setUseTime(LocalDateTime.now());
            item.setUseType(CouponEnum.COUPON_USE_TYPE_HAS_USED.getCode());
            Long couponId = item.getCouponId();
            Long count = couponMap.get(couponId);
            count = Objects.isNull(count) ? 1 : count + 1;
            couponMap.put(couponId, count);
        });
        couponService.updateUseCount(couponMap);
        couponHistoryService.updateBatchById(list);
    }

    @Override
    @Transactional
    @PreventRepeatSubmit(key = "vo.orderSn", openSpEL = true)
    public void updateCouponHistory(CouponUpdateVo vo) {
        List<CouponHistoryEntity> list = couponHistoryService.listByOrderSn(vo.getOrderSn());
        List<CouponSkuVo> reduceVoList = vo.getList();
        list.forEach(history -> {
            reduceVoList.stream().filter(reduce -> Objects.equals(reduce.getCouponId(), history.getCouponId()) &&
                    reduce.getSkuId().equals(history.getSkuId())).findFirst().ifPresent(reduce -> {
                        history.setOrderSn(reduce.getOrderSn());
            });
        });
        couponHistoryService.updateBatchById(list);
    }

    @Override
    @Transactional
    public void returnCoupon(String orderSn) {
        couponHistoryService.updateByOrderSn(orderSn);

    }

    @Override
    public PageUtils getGoodList(CouponEsFeignQuery query) {
        String merchantId = authTokenService.getUserInfo().getMerchantId();
        query.setMerchantId(merchantId);
        Long couponId = query.getCouponId();
        List<String> skuIds = new ArrayList<>();
        if (query.getType() == 1) {
            skuIds.addAll(couponSkuService.getByCouponId(couponId));
        } else if (query.getType() == 2) {
            skuIds.addAll(skuFullReductionService.getListByMerchantId(merchantId));
        } else if (query.getType() == 3) {
            List<String> list = skuLadderService.getListByMerchantId(merchantId);
            skuIds.addAll(list);
        } else {
            throw new WebDisplayException("CouponApplicationServiceImpl -> getGoodList :参数异常");
        }
        query.setSkuIds(skuIds);
        return JsonUtils.transToArrayClassPage(searchFeignService.skuCouponSearch(query), EsSkuEntity.class);
    }

    private static String getCouponReceiveKey(String memberId) {
        return CouponConstant.COUPON_RECEIVE_KEY_LOCK + memberId;
    }
}
